﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using Helper;
using Highlearner_API;

using Logging;


namespace Highlearner
{
	enum EState
	{
		Disconnected,
		Connected,
		Downloading,
	}

	public partial class FormMain : Form
	{
		private delegate void SetStatusDelegate(EState a_eState);

		private bool m_bCoursesLoaded = false;
	
		private Miner_Highlearn.frm_Log FormLog;
		private CCourse SelectedCourse
		{
			get
			{
				return Manager.DataCenter.Courses[listViewCourses.SelectedItems[0].Text];
			}
		}
		private CFolderItem m_oCurrentFolder = null;

		private CListViewAnimator m_oAnimator;

		// States whether the tree view is populating. Good for knowing when to ignore certain events (like AfterCheck)
		private bool m_bTreeViewPopulating = false;

        private CManager Manager = new CManager();

		public FormMain()
		{
			// Reset the downloads directory
			if (Properties.Settings.Default.SavePath == "")
			{
				Properties.Settings.Default.SavePath =
					Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\HighlearnerDownloads";
			}

			InitializeComponent();

			FormLog = new Miner_Highlearn.frm_Log();
			FormLog.Show();
			//edt_Log = FormLog.edt_Log;

			m_oAnimator = new CListViewAnimator(listViewCourses);

			CLogger.StartLogging(CUtilities.ConfigurationDirectory + "Log.csv");
		}

		private void FormMain_Load(object sender, System.EventArgs e)
		{
			listViewCourses.Items.Clear();
			m_bCoursesLoaded = false;

			Manager.OnStateChanged += new StateChangedDelegate(Manager_OnStateChanged);
			Manager.OnDownloadProgress += new DownloadProgressDelegate(Manager_OnDownloadProgress);
			Manager.OnError += new ErrorDelegate(Manager_OnError);
			Manager.Initialize();


			// Fix the miner crap. Remove this someday
			Manager.Executer.Core.logger = new Helper.Logger();
			Manager.Executer.Core.logger.edt_Log = FormLog.edt_Log;
			Manager.Executer.Core.logger.frm_Parent = this;
			Manager.Executer.Core.logger.file_path = CUtilities.ConfigurationDirectory + "Log.txt";
			if (File.Exists(Manager.Executer.Core.logger.file_path))
			{
				File.Delete(Manager.Executer.Core.logger.file_path);
			}

			if (Properties.Settings.Default.Username == "")
			{
				if (ShowSettings() != DialogResult.OK)
				{
					CLogger.LogMessage("Settings Error. Exiting...");
					Application.Exit();
					return;
				}
			}

			labelTop.Text = "ברוכים הבאים, " + Properties.Settings.Default.Username;

			// Get the events this form needs
			Manager.DataCenter.OnCourseListUpdated += new CDataCenter.CoursesListUpdatedDelegate(DataCenter_OnCourseListUpdated);
			Manager.DataCenter.OnCourseUpdated += new CDataCenter.CourseUpdatedDelegate(DataCenter_OnCourseUpdated);

			// Start the connection process
			Manager.Connect();

			if (Properties.Settings.Default.CheckUpdatesAutomatically)
			{
				CheckUpdates();
			}
		}

		void Manager_OnDownloadProgress(int totalFilesCount, int downloadedFilesCount, CFileItem a_oCurrentFile)
		{
			this.Invoke(new DownloadProgressDelegate(Manager_OnDownloadProgressSafe), totalFilesCount, downloadedFilesCount, a_oCurrentFile);
		}

		void Manager_OnDownloadProgressSafe(int totalFilesCount, int downloadedFilesCount, CFileItem a_oCurrentFile)
		{
			int l_iPercent = 0;
			if (Manager.HighlearnerState == EHighlearnerState.DownloadingCourse)
			{
				l_iPercent = (int)(((double)downloadedFilesCount / (double)totalFilesCount) * 100);
				toolStripProgressBar.Value = l_iPercent;

				UpdateCurrentStatus(String.Format("מוריד קבצים... (קובץ {0} מתוך {1} - {2})", downloadedFilesCount, totalFilesCount, a_oCurrentFile.Name));
			}
		}

		void Manager_OnError(EHighlearnerError a_eError)
		{
			switch (a_eError)
			{
				case EHighlearnerError.ConnectingFailed :
					UpdateCurrentStatus("ארעה שגיאה בהתחברות. האם כתבת את סיסמתך נכון?");
					break;
				case EHighlearnerError.FilesFailedDownloading :
					FormFailedFiles.DisplayFileList(Manager.FailedFiles);
					break;

			}
		}

		private void SetGUIState(EHighlearnerState a_eState)
		{
			switch (a_eState)
			{
				case EHighlearnerState.Disconnected:
					UpdateSettingsOnStatus();
					UpdateGeneralStatus("מנותק");
					UpdateCurrentStatus("");

					toolStripStatusLabelGeneralStatus.ForeColor = Color.Red;
					break;

				case EHighlearnerState.Connecting:
					UpdateCurrentStatus("");
					UpdateGeneralStatus("מתחבר...");
					break;

				case EHighlearnerState.Idle:
					UpdateGeneralStatus("מוכן");
					UpdateCurrentStatus("");
					toolStripStatusLabelGeneralStatus.ForeColor = Color.Green;

					toolStripProgressBar.Enabled = false;// Value = 0;
					toolStripStatusLabelCourseName.Text = "";

					// Stop the loading animation
					m_oAnimator.ClearItems();

					break;

				case EHighlearnerState.RefreshingCoursesList:
					UpdateCurrentStatus("מעדכן רשימת קורסים...");
					m_bCoursesLoaded = false;

					toolStripProgressBar.Value = 0;
		
					break;

				case EHighlearnerState.RefreshingCourseItems:
					UpdateCurrentStatus("מעדכן קורסים...");
					toolStripProgressBar.Value = 0;

					break;

				case EHighlearnerState.DownloadingCourse:
					UpdateCurrentStatus("מוריד קבצים...");
					toolStripProgressBar.Value = 0;

					break;

// 				case EHighlearnerState.DownloadFinished :
// 					toolStripProgressBar.Value = toolStripProgressBar.Maximum;
// 
// 					break;
			}

			buttonStartDownloading.Enabled = (a_eState == EHighlearnerState.Idle);
			timerHoldOn.Enabled = (a_eState == EHighlearnerState.RefreshingCoursesList);
			ToolStripMenuItemConnect.Enabled = (a_eState == EHighlearnerState.Disconnected);
		}

		void Manager_OnStateChanged(EHighlearnerState a_eNewState, string a_sMessage)
		{
			this.Invoke(new StateChangedDelegate(Manager_OnStateChangedSafe), a_eNewState, a_sMessage);
		}
		void Manager_OnStateChangedSafe(EHighlearnerState a_eNewState, string a_sMessage)
		{
			SetGUIState(a_eNewState);
			//UpdateCurrentStatus(a_sMessage);
		}

		void DataCenter_OnCourseUpdated(CCourse a_oFreshCourse)
		{
			this.Invoke(new CDataCenter.CourseUpdatedDelegate(DataCenter_OnCourseUpdatedSafe), a_oFreshCourse);
		}
		void DataCenter_OnCourseUpdatedSafe(CCourse a_oFreshCourse)
		{
			if (SelectedCourse.Name == a_oFreshCourse.Name)
				RefreshSelectedCourseDetails();
		}

		void DataCenter_OnCourseListUpdated()
		{
			this.Invoke(new CDataCenter.CoursesListUpdatedDelegate(DataCenter_OnCourseListUpdatedSafe));
		}
		void DataCenter_OnCourseListUpdatedSafe()
		{
			RefreshCoursesList();
		}


		private void UpdateCurrentStatus(String a_sMessage)
		{
			toolStripStatusLabelCurrentStatus.Text = a_sMessage;
		}
		private void UpdateGeneralStatus(String a_sMessage)
		{
			toolStripStatusLabelGeneralStatus.Text = a_sMessage;
		}


		private void SetCourseListItemLooks(ListViewItem a_oItem, CCourse a_oCourse)
		{
			// Set the font
			if (!(a_oCourse.DataRetrieved == ERetrievedState.NotRetrieved))
				a_oItem.Font = new Font(a_oItem.Font, FontStyle.Bold);
			else
				a_oItem.Font = new Font(a_oItem.Font, FontStyle.Regular);

			// Now set the icon
			a_oItem.ImageIndex = (int)Manager.DataCenter.Courses[a_oItem.Text].DataRetrieved;

			if (!a_oCourse.CourseExists)
			{
				a_oItem.ForeColor = Color.Gray;
				a_oItem.ImageIndex = 3; // Put a gray icon
			}
			else
			{
				a_oItem.ForeColor = Color.Black;
			}
		}

		#region GUI - Datacenter Update methods
		private void UpdateTreeNode(TreeNode a_oNode, CFolderItem a_oFolder)
		{
			// Bad encapsulation alert!
			// The tree nodes are created in 2 different places - Here and in the RefreshSelectedCourseDetails method.

			TreeNode l_oNode;
			
			a_oNode.Checked = a_oFolder.Download;

			foreach (CFolderItem l_oFolder in a_oFolder.Folders.Values)
			{
				l_oNode = new TreeNode(l_oFolder.Name);
				l_oNode.Name = l_oFolder.Name;

				a_oNode.Nodes.Add(l_oNode);
				UpdateTreeNode(l_oNode, l_oFolder);
			}
		}

		/// <summary>
		/// Queries the Highlearn system for data about the course
		/// </summary>
		private void RefreshCourseInformation(string a_sCourseName)
		{
			if (Manager.HighlearnerState == EHighlearnerState.Idle)
			{
				Manager.RefreshCourseDetails(a_sCourseName);
				m_oAnimator.AddItem(listViewCourses.Items.Find(a_sCourseName, false)[0], a_sCourseName);
			}
		}

		/// <summary>
		/// Refreshes the GUI according to the new selected course.
		/// </summary>
		private void RefreshSelectedCourseDetails()
		{
			TreeNode l_oNode;
			CCourse l_oIteratedCourse;

			// Not sure why this happens, but the function shouldn't work when no item is selected
			if (listViewCourses.SelectedItems.Count == 0)
			{
 				Manager.Executer.Core.logger.WriteLn("RefreshCourseDetails Ignoring Request (no item selected)");
				return;
			}

			treeViewFolders.Nodes.Clear();
			checkedListBoxFiles.Items.Clear();

			if (listViewCourses.SelectedItems.Count > 0)
			{
				m_bTreeViewPopulating = true;
				foreach (CFolderItem l_oFolder in SelectedCourse.Data.Folders.Values)
				{
					// Bad encapsulation alert!
					// The tree nodes are created in 2 different places - Here and in the UpdateTreeNode method.
					l_oNode = treeViewFolders.Nodes.Add(l_oFolder.Name);
					l_oNode.Name = l_oFolder.Name;
					UpdateTreeNode(l_oNode, l_oFolder);
				}
				m_bTreeViewPopulating = false;

				foreach (ListViewItem l_oItem in listViewCourses.Items)
				{
					l_oIteratedCourse = Manager.DataCenter.Courses[l_oItem.Text];
					SetCourseListItemLooks(l_oItem, l_oIteratedCourse);
				}
			}
		}

		private void RefreshFilesDetails()
		{
			int l_iFileIndex;

			if (treeViewFolders.SelectedNode != null)
			{
				m_oCurrentFolder = SelectedCourse.GetFolderAt(treeViewFolders.SelectedNode.FullPath);

				checkedListBoxFiles.Items.Clear();

				foreach (CFileItem l_oFile in m_oCurrentFolder.Files.Values)
				{
					l_iFileIndex = checkedListBoxFiles.Items.Add(l_oFile.ToString());
					checkedListBoxFiles.SetItemChecked(l_iFileIndex, l_oFile.Download);
				}
			}
		}

		private void RefreshFoldersCheckedState()
		{
			foreach (CFolderItem l_oFolder in SelectedCourse.Data.Folders.Values)
			{
//				treeViewFolders.Nodes.IndexOfKey(l_oFolder.Name);
				RefreshFoldersCheckedState(l_oFolder, treeViewFolders.Nodes[l_oFolder.Name]);
			}
		}

		private void RefreshFoldersCheckedState(CFolderItem a_oFolder, TreeNode a_oNode)
		{
			TreeNode[] l_oNode;

			a_oNode.Checked = a_oFolder.Download;

			foreach (CFolderItem l_oFolder in a_oFolder.Folders.Values)
			{
				l_oNode = a_oNode.Nodes.Find(l_oFolder.Name, false);
				RefreshFoldersCheckedState(l_oFolder, l_oNode[0]);
			}
		}
		#endregion

		private void RefreshCoursesList()
		{
			ListViewItem l_oItem;

			foreach (CCourse l_oCourse in Manager.DataCenter.Courses.Values)
			{
				l_oItem = listViewCourses.FindItemWithText(l_oCourse.ToString());
				if (l_oItem == null)
				{
					l_oItem = listViewCourses.Items.Add(l_oCourse.ToString());
					l_oItem.Name = l_oCourse.ToString();
					l_oItem.Checked = l_oCourse.Download;
					l_oItem.ImageIndex = (int)l_oCourse.DataRetrieved;
				}

				SetCourseListItemLooks(l_oItem, l_oCourse);
			}

			if (listViewCourses.SelectedIndices.Count == 0)
			{
				if (listViewCourses.Items.Count > 0)
					listViewCourses.Items[0].Selected = true;
			}

			m_bCoursesLoaded = true;
			timerHoldOn.Stop();
			labelHoldOn.Visible = false;
		}

		private void UpdateSettingsOnStatus()
		{
			UpdateCurrentStatus("הקבצים יישמרו אל " + Properties.Settings.Default.SavePath);
		}

		private bool CheckUpdates()
		{
			try
			{
				AutoUpdater.CAutoUpdater l_oUpdater = new AutoUpdater.CAutoUpdater("http://spofer.com/Highlearner/Latest.xml", true);

				if (l_oUpdater.CompareVersions(l_oUpdater.LatestVersion, Application.ProductVersion) == 1)
				{
					if (MessageBox.Show(
						"?האם ברצונך לעדכן" + " ," + "Highlearner" + " ישנה גרסה מעודכנת יותר של",
						"Version update",
						MessageBoxButtons.YesNo,
						MessageBoxIcon.Question) == DialogResult.Yes)
					{
						new FormUpdate(l_oUpdater).Show();
					}
					return true;
				}
			}
			catch (Exception)
			{
				CLogger.LogMessage("Failed checking for updates!");
			}

			return false;
		}

		private DialogResult ShowSettings()
		{
			DialogResult l_oResult;
			FormSettings l_oSettings = new FormSettings();
			l_oSettings.ShowInTaskbar = false;
			l_oResult = l_oSettings.ShowDialog();
			UpdateSettingsOnStatus();

			Manager.DataCenter.AllowSaving = Properties.Settings.Default.SaveUserCourses;

			return l_oResult;
		}

		private void listViewCourses_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			ListViewItem l_oItem;

			if (e.Button == MouseButtons.Left)
			{
				l_oItem = listViewCourses.GetItemAt(e.X, e.Y);
				if (m_bCoursesLoaded)
				{
					if (l_oItem.Index > -1)
					{
						RefreshCourseInformation(l_oItem.Text);
					}
				}
				else
				{
					l_oItem.Checked = false;
				}
			}
		}

		private void listViewCourses_SelectedIndexChanged(object sender, EventArgs e)
		{
			RefreshSelectedCourseDetails();
		}

		private void treeViewFolders_AfterSelect(object sender, TreeViewEventArgs e)
		{
			RefreshFilesDetails();
		}

		private void buttonStartDownloading_Click(object sender, EventArgs e)
		{
			Manager.Executer.SavePath = Properties.Settings.Default.SavePath;

			foreach (ListViewItem l_oItem in listViewCourses.Items)
			{
				Manager.DataCenter.Courses[l_oItem.Text].Download = l_oItem.Checked;
			}

			Manager.Download();
		}

		private void treeViewFolders_AfterCheck(object sender, TreeViewEventArgs e)
		{
			// Prevent running when the tree is populated
			if (!m_bTreeViewPopulating)
			{
				// Get the relevant folder
				CFolderItem l_oFolder = Manager.DataCenter.Courses[listViewCourses.SelectedItems[0].Text].Data.GetFolder(e.Node.FullPath);

				if ((e.Action == TreeViewAction.ByKeyboard) || (e.Action == TreeViewAction.ByMouse))
				{
					// And set!
					l_oFolder.Download = e.Node.Checked;

					RefreshFoldersCheckedState(l_oFolder, e.Node);
					RefreshFilesDetails();
				}
			}
		}

		private void SetCheckedState(Control a_oControl, Boolean a_bState)
		{
			if (a_oControl == listViewCourses)
			{
				foreach (ListViewItem l_oItem in listViewCourses.Items)
				{
					l_oItem.Checked = a_bState;
				}
			}
			if (a_oControl == checkedListBoxFiles)
			{
				if (m_oCurrentFolder != null)
				{
					m_oCurrentFolder.Download = a_bState;
					RefreshFilesDetails();
				}
			}
			if (a_oControl is TreeView)
			{
				foreach (CFolderItem l_oFolder in SelectedCourse.Data.Folders.Values)
				{
					l_oFolder.Download = a_bState;
				}
				foreach (CFileItem l_oFile in SelectedCourse.Data.Files.Values)
				{
					l_oFile.Download = a_bState;
				}

				RefreshFoldersCheckedState();
			}
		}

		private void toolStripMenuItemMarkAll_Click(object sender, EventArgs e)
		{
			SetCheckedState(contextMenuStripRight.SourceControl, true);
		}
		private void toolStripMenuItemUnMarkAll_Click(object sender, EventArgs e)
		{
			SetCheckedState(contextMenuStripRight.SourceControl, false);
		}
		private void toolStripMenuItemDownloadCourseInformation_MouseDown(object sender, MouseEventArgs e)
		{
			if (listViewCourses.SelectedItems.Count > 0)
			{
				RefreshCourseInformation(SelectedCourse.Name);
			}
		}

		private void checkedListBoxFiles_ItemCheck(object sender, ItemCheckEventArgs e)
		{
			if (m_oCurrentFolder != null)
			{
				m_oCurrentFolder.Files[checkedListBoxFiles.Items[e.Index].ToString()].Download = (e.NewValue == CheckState.Checked);
			}
		}

		private void contextMenuStripFolders_Click(object sender, EventArgs e)
		{

		}

		private void אודותToolStripMenuItem_Click(object sender, EventArgs e)
		{
			(new frm_About()).Show();
		}
		private void יציאהToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Application.Exit();
		}

		private void listViewCourses_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right)
			{
				if (listViewCourses.GetItemAt(e.X, e.Y) != null)
				{
					contextMenuStripCourses.Show(listViewCourses, e.X, e.Y);
				}
			}
		}

		private void הגדרותToolStripMenuItem_Click(object sender, EventArgs e)
		{
			ShowSettings();

			if (Manager.Executer.CONFIG_USERNAME != Properties.Settings.Default.Username)
			{
				Manager.Disconnect();

				// This should reload the user and reinitizlize the hl
				Manager.Connect();
			}
		}

		private void בדוקעדכוניםToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (!CheckUpdates())
			{
				MessageBox.Show("בידך הגרסה העדכנית ביותר", "עדכון גרסה", MessageBoxButtons.OK, MessageBoxIcon.Information);

			}

		}

		private void buttonOpenDownloadsDirectory_Click(object sender, EventArgs e)
		{
			// Check what happens if there is no security
			if (Directory.Exists(Properties.Settings.Default.SavePath))
			{
				System.Diagnostics.Process.Start(Properties.Settings.Default.SavePath);
			}
		}

		private void panelFilesManagment_Resize(object sender, EventArgs e)
		{
			int l_iSize = panelControl.Width;
			// | 3 | Button | 1 | 1 | Buttion | 3 |
			int l_iButtonSize = ((l_iSize - 10) / 2);
			
			buttonOpenDownloadsDirectory.Left = 3;
			buttonOpenDownloadsDirectory.Width = l_iButtonSize;
			buttonStartDownloading.Left = buttonOpenDownloadsDirectory.Left + l_iButtonSize + 2;
			buttonStartDownloading.Width = l_iButtonSize;
		}

		private void timerHoldOn_Tick(object sender, EventArgs e)
		{
			labelHoldOn.Visible = !labelHoldOn.Visible;
		}

		private void נקהקורסיםישניםToolStripMenuItem_Click(object sender, EventArgs e)
		{
			/*
			 * Removed for this version. Maybe next one!
			 * 
			m_oCore.DataCenter.CleanupOldCourses();

			listViewCourses.Clear();

			CoursesLoaded();
			*/
		}

		private void ToolStripMenuItemConnect_Click(object sender, EventArgs e)
		{
			Manager.Connect();
		}

		private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
		{
			Manager.Disconnect();
		}
	}
}
